package com.rengwuxian.coursecoroutines._3_scope_context

import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineExceptionHandler
import kotlinx.coroutines.CoroutineName
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import kotlin.coroutines.ContinuationInterceptor
import kotlin.coroutines.EmptyCoroutineContext

/**
 * CoroutineContext的加减和get()
 * CoroutineContext的+、[Job/ContinuationInterceptor/xxx]、minusKey()
 *
 * CoroutineContext的管理 +plus -minus 和获取[]的原理 --- operator 操作符重载 operator fun
 * +号（plus） 合并CoroutineContext的，合并同类项，移除 + 号左边的。（要么同类项直接相加则会直接报错，除去CoroutineName和CoroutineExceptionHandler）两两组成新的CombinedContext
 * 顺序是有可能调整的。
 * 本例子代码输出：保留了右边的job2
 * job1: JobImpl{Active}@1d16f93d, job2: JobImpl{Active}@67b92f0a
 * CoroutineContext: [CoroutineName(MyCoroutine), JobImpl{Active}@67b92f0a, Dispatchers.IO]
 *
 *  常见的ContinuationInterceptor都是实现了CoroutineDispatcher
 *  取CoroutineDispatcher的代码：val interceptor: CoroutineDispatcher? = coroutineContext[CoroutineDispatcher]
 *  虽然是试验性的API，但是绝对安全
 *
 *  再比如取Job：
 *  val job: Job? = coroutineContext[Job]
 *  为什么可以直接填Job，是companion object的特型，可以给每个类型的里面设置一个全局的对象，可以直接简写访问。源码如下：
 *  public companion object Key : CoroutineContext.Key<Job>
 *
 *  如果想删除coroutineContext中的某种CoroutineContext，可以使用coroutineContext.minusKey(Job)
 *  println("coroutineContext: $coroutineContext")
 *  println("coroutineContext after minusKey() ${coroutineContext.minusKey(Job)}") // 少了StandaloneCoroutine，就是Job对象
 *  输出：
 *  coroutineContext: [CoroutineName(MyCoroutine), StandaloneCoroutine{Active}@1c39107f, Dispatchers.IO]
 *  coroutineContext after minusKey() [CoroutineName(MyCoroutine), Dispatchers.IO]
 *
 */
@OptIn(ExperimentalStdlibApi::class)
fun main() = runBlocking<Unit> {
  val job1 = Job()
  val job2 = Job()
  val scope = CoroutineScope(Dispatchers.IO + job1
      + CoroutineName("MyCoroutine") + job2)
  // [[CoroutineName(MyCoroutine), job2], Dispatchers.IO]
  println("job1: $job1, job2: $job2")
  println("CoroutineContext: ${scope.coroutineContext}")
  scope.launch {
    val job: Job? = coroutineContext[Job]
    val interceptor: CoroutineDispatcher? = coroutineContext[CoroutineDispatcher]
    println("coroutineContext: $coroutineContext")
    println("coroutineContext after minusKey() ${coroutineContext.minusKey(Job)}") // 少了StandaloneCoroutine，就是Job对象
  }
  delay(10000)
}